package controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.JOptionPane;

import model.AppModel;
import model.ModelException;
import model.Token;
import view.TokenView;
import view.ViewHelpers;

/**
 * Controls the Tokens view
 * 
 * This controller has a reference to the main model, and the current view it is working on.
 * It assigns handlers to events for the show usage, view system tokens, add, delete
 * buttons and specifies the actions to invoke upon triggering these events. 
 * 
 * @author MUSAB
 *
 * @version $Revision: 1.0 $
 */
public class TokenViewController {
	
	// Application model, view and main controller
	private AppModel model;
	
	// The view to work on
	private TokenView view;
	
	// Description text
	private String systemTokensDescriptionText;
	

	/**
	 * Constructor takes the app model
	 * @param model
	 */
	public TokenViewController(AppModel model) {
		
		this.model = model; 
		view = new TokenView();
		
		setupView();
		assignHandlersToEvents();
		view.showDialog();
	}
	
	/**
	 * Load tokens into view
	 */
	private void refreshView(){
		
		// Clear the current list
		for (int i = view.getUserTokens().getRowCount() - 1; i >= 0; i--) {
		    view.getUserTokens().removeRow(i);
		}
		
		// Get the tokens and add them
		String[] tokens = {};
		for(Token token : model.getUser().getTokens()){
			view.getUserTokens().addRow(new String[]{
					token.getKey(), token.getValue()
			});
		}
		
		// Empty the text fields
		view.getNewKey().setText("");
		view.getNewValue().setText("");
	}

	/**
	 * Validates the inputs for new key and new value
	 * 
	 * @param newValueString New key 
	 * @param newKeyString New value
	 * @return Boolean
	 */
	private Boolean areValidInputs(String newKeyString, String newValueString){
		
		// Key contains spaces
		if (newKeyString.contains(" ")){
			ViewHelpers.alertError("Key can not contain spaces");
			return false;
		}
				
		// Empty strings
		if (newKeyString.isEmpty() || newValueString.isEmpty()){
			ViewHelpers.alertError("The key or value should not be empty");
			return false;
		}
		
		// User key already exists
		if (model.getUser().getTokenHashMap().containsKey(newKeyString)){
			ViewHelpers.alertError("You have already defined this key, please use a different name");
			return false;
		}
		
		// Invalid key because it exists as a system key
		if (model.getSystemDefinedTokens().containsKey(newKeyString)){
			ViewHelpers.alertError("'"+newKeyString+"' is a system defined key, please use a different key name");
			return false;
		}
		
		return true;
				
	}
	
	
	/**
	 * Sets up the view
	 */
	private void setupView() {
		
		refreshView();
		
		// Setup description text
		systemTokensDescriptionText = "Following are the system defined tokens which you can not override:\n";
		
		Iterator<Entry<String, String>> it = model.getSystemDefinedTokens().entrySet().iterator();
	    while (it.hasNext()) {
	        Map.Entry pairs = (Map.Entry)it.next();
	        systemTokensDescriptionText = systemTokensDescriptionText
	        		+ "\n" + pairs.getKey() + ": "
	        		+ pairs.getValue();
	        it.remove(); // avoids a ConcurrentModificationException
	    }
		
	}

	/**
	 * Adds handlers to events for the token view
	 */
	private void assignHandlersToEvents() {
		
		// Show usage
		view.getUsageBtn().addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				actionShowUsageHelp();
			}
		});
		
		// View system tokens 
		view.getViewSystemTokensBtn().addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				actionShowSystemTokensDescription();
			}
		});
		
		// Add new token
		view.getAddNewTokenBtn().addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				actionAddNewToken();
			}
		});
		
		// Add delete token
		view.getDeleteSelectedBtn().addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				actionDeleteSelectedToken();
			}
		});
	}

	/**
	 * Shows the usage help popup
	 */
	protected void actionShowUsageHelp() {
		
		String message = "The tokens format is: ${key}\n\n"+
				"For example, the following text in your email body:\n"+
				"Hi! The date right now is ${date} and the time is ${time}.\n\n"+
				"will be converted to:\n"+
				"Hi! The date right now is 23-12-2013 and the time is 1:15 pm.";
		
		ViewHelpers.alertInfo(message, "Tokens usage");
	}

	/**
	 * Deletes the selected token
	 */
	protected void actionDeleteSelectedToken() {
		
		int index = view.getUserTokensTable().getSelectedRow();
		
		if (index == -1){
			ViewHelpers.alertError("No tokens were actually selected");
			return;
		}

		// delete it
		String key = (String) view.getUserTokens().getValueAt(index, 0);
		
		try {
			model.getUser().deleteToken(key);
		} catch (ModelException e) {
			ViewHelpers.alertError("The token could not be deleted for some reason, please try again");
			e.printStackTrace();
			return;
		}
		
		// refresh
		refreshView();
	}

	/**
	 * Create a new token
	 */
	protected void actionAddNewToken() {
		
		// Sanitize user input
		String newKeyString = view.getNewKey().getText().toLowerCase().trim();
		String newValueString = view.getNewValue().getText().toLowerCase().trim();
				
		// validate input
		if (!areValidInputs(newKeyString, newValueString)){
			return;
		}
		
		// Create the key
		try {
			model.getUser().createNewToken(newKeyString, newValueString);
		} catch (ModelException e) {
			ViewHelpers.alertError("Could not create key for some reason, please try again");
			return;
		}
		
		// refresh the view
		refreshView();
		
	}

	/**
	 * Shows the system tokens description popup with information
	 */
	protected void actionShowSystemTokensDescription() {
		
		JOptionPane.showMessageDialog(null, systemTokensDescriptionText, "System defined tokens", JOptionPane.INFORMATION_MESSAGE);
	}
	

}
